package com.oa.erp.pur.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mdp.core.err.BizException;
import com.mdp.core.service.BaseService;
import com.mdp.safe.client.entity.User;
import com.mdp.safe.client.utils.LoginUtils;
import com.oa.erp.pur.entity.Order;
import com.oa.erp.pur.entity.OrderDetail;
import com.oa.erp.pur.entity.RequireDetail;
import com.oa.erp.pur.mapper.OrderMapper;
import com.oa.erp.pur.vo.DetailLinkVo;
import com.oa.erp.pur.vo.OrderAddVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author maimeng-mdp code-gen
 * @since 2023年10月8日
 */
@Service
public class OrderService extends BaseService<OrderMapper, Order> {
    static Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Lazy
    @Autowired
    private OrderDetailService orderDetailService;


    @Autowired
    private RequireDetailService requireDetailService;

    /**
     * 自定义查询，支持多表关联
     *
     * @param page 分页条件
     * @param ew   一定要，并且必须加@Param("ew")注解
     * @param ext  如果xml中需要根据某些值进行特殊处理，可以通过这个进行传递，非必须，注解也可以不加
     * @return
     */
    public List<Map<String, Object>> selectListMapByWhere(IPage page, QueryWrapper ew, Map<String, Object> ext) {
        return baseMapper.selectListMapByWhere(page, ew, ext);
    }

    /**
     * 添加一条采购订单
     *
     * @param orderAddVo
     */
    @Transactional
    public void insertOrder(OrderAddVo orderAddVo) {
        User user = LoginUtils.getCurrentUserInfo();
        //设置申购机构编号，与名称
        Order main = orderAddVo.getOrder();
        main.setPurBranchId(user.getBranchId());
        main.setPurBranchName(user.getBranchName());
        this.insert(main);
        //设置资产采购明细表
        List<OrderDetail> batchInsertDetails = new ArrayList<>();
        for (OrderDetail orderDetail : orderAddVo.getOrderDetailList()) {
            //设置关联采购单主表Id
            orderDetail.setPurOrderId(main.getId());
            //设置创建人 创建时间
            orderDetail.setCreateUserid(user.getUserid());
            orderDetail.setCreateTime(new Date());
            orderDetail.setLastEditUserid(user.getUserid());
            orderDetail.setLastEditTime(new Date());
            if (!StringUtils.hasText(orderDetail.getId())) {
                orderDetail.setId(orderDetailService.createKey("id"));
            }

            //设置到达数量默认为0
            orderDetail.setReachNum(new BigDecimal(0));
            batchInsertDetails.add(orderDetail);
        }
//        orderDetailService.batchInsert(batchInsertDetails);
        orderDetailService.saveOrUpdateBatch(batchInsertDetails); // 不知道有没有id

        List<DetailLinkVo> detailLinkVos = orderAddVo.getDetailLinks();
        detailLinkVos = detailLinkVos == null ? new ArrayList<>() : detailLinkVos;
        if (detailLinkVos != null && detailLinkVos.size() > 0) {
            List<RequireDetail> requireDetails = detailLinkVos.stream().map(l -> {
                RequireDetail detail = new RequireDetail();
                detail.setOrderId(orderAddVo.getOrder().getId());
                detail.setOrderDetailId(l.getOrderDetailId());
                detail.setId(l.getRequireDetailId());
                return detail;
            }).collect(Collectors.toList());
            requireDetailService.batchUpdateOrderId(requireDetails);
        }
    }

    @Transactional
    public void updateOrder(OrderAddVo orderAddVo) {
        User user = LoginUtils.getCurrentUserInfo();
        String orderId = orderAddVo.getOrder().getId();
        this.updateByPk(orderAddVo.getOrder());
        List<OrderDetail> batchInsertDetails = new ArrayList<>();
        List<OrderDetail> batchUpdateDetails = new ArrayList<>();
        List<OrderDetail> batchDelDetails = new ArrayList<>();

        OrderDetail query = new OrderDetail();
        query.setPurOrderId(orderId);
        List<OrderDetail> orderDetailsDb = this.orderDetailService.selectListByWhere(query);
        Map<String, OrderDetail> orderDetailsDbMap = new HashMap<>();
        for (OrderDetail orderDetail : orderDetailsDb) {
            orderDetailsDbMap.put(orderDetail.getId(), orderDetail);
        }

        Map<String, OrderDetail> detailMap = new HashMap<>();
        for (OrderDetail orderDetail : orderAddVo.getOrderDetailList()) {
            if (orderDetailsDbMap.containsKey(orderDetail.getId())) {
                batchUpdateDetails.add(orderDetail);
            } else {
                if (!StringUtils.hasText(orderDetail.getId())) {
                    orderDetail.setId(orderDetailService.createKey("id"));
                }
                batchInsertDetails.add(orderDetail);
            }
            detailMap.put(orderDetail.getId(), orderDetail);
        }
        for (OrderDetail orderDetail : orderDetailsDb) {
            if (!detailMap.containsKey(orderDetail.getId())) {
                batchDelDetails.add(orderDetail);
            }
        }
        if (batchInsertDetails.size() > 0) {
            for (OrderDetail orderDetail : batchInsertDetails) {
                orderDetail.setPurOrderId(orderId);
                orderDetail.setCreateTime(new Date());
                orderDetail.setLastEditTime(new Date());
                orderDetail.setLastEditUserid(user.getUserid());
                orderDetail.setBranchId(user.getBranchId());
            }
            this.orderDetailService.batchInsert(batchInsertDetails);
        }
        if (batchUpdateDetails.size() > 0) {
            for (OrderDetail orderDetail : batchUpdateDetails) {
                orderDetail.setLastEditTime(new Date());
                orderDetail.setLastEditUserid(user.getUserid());
            }
            this.orderDetailService.batchUpdate(batchUpdateDetails);
        }

        List<DetailLinkVo> detailLinkVos = orderAddVo.getDetailLinks();
        detailLinkVos = detailLinkVos == null ? new ArrayList<>() : detailLinkVos;
        if (batchDelDetails.size() > 0) {
            this.orderDetailService.batchDelete(batchDelDetails);
            detailLinkVos = detailLinkVos.stream().filter(i -> !batchDelDetails.stream().filter(m -> m.getId().equals(i.getOrderDetailId())).findAny().isPresent()).collect(Collectors.toList());
            requireDetailService.batchUpdateOrderIdToNullByOrderDetailIds(batchDelDetails.stream().map(i -> i.getId()).collect(Collectors.toList()));
        }
        if (detailLinkVos != null && detailLinkVos.size() > 0) {
            List<RequireDetail> requireDetails = detailLinkVos.stream().map(l -> {
                RequireDetail detail = new RequireDetail();
                detail.setOrderId(orderAddVo.getOrder().getId());
                detail.setOrderDetailId(l.getOrderDetailId());
                detail.setId(l.getRequireDetailId());
                return detail;
            }).collect(Collectors.toList());
            requireDetailService.batchUpdateOrderId(requireDetails);
        }


    }


    @Transactional
    public void deleteOrder(Order order) {
        //1.删除资产申购单主表数据
        this.deleteByPk(order);
        Map<String, Object> params = new HashMap<>();
        params.put("purOrderId", order.getId());
        //删除资产申购单明细表数据
        orderDetailService.deleteByWhere((OrderDetail) params);
    }

    @Transactional
    public void batchDeleteOrder(List<Order> orders) {
        //1.删除资产申购单主表数据
//        this.batchDelete(orders);
        baseMapper.deleteBatchIds(orders);
        //删除资产申购单明细表数据
        orderDetailService.batchDeleteDetailByPurOrderId(orders);
    }


    public void updateReachNumByOrderId(List<String> orderIds) {

        baseMapper.updateDetailReachNumByOrderId(orderIds);
        baseMapper.updateReachNumByOrderId(orderIds);
    }

    /**
     * 流程审批过程中回调该接口，更新业务数据
     * 如果发起流程时上送了restUrl，则无论流程中是否配置了监听器都会在流程发生以下事件时推送数据过来
     * eventName: PROCESS_STARTED 流程启动完成 全局
     * PROCESS_COMPLETED 流程正常结束 全局
     * PROCESS_CANCELLED 流程删除 全局
     * create 人工任务启动
     * complete 人工任务完成
     * assignment 人工任务分配给了具体的人
     * delete 人工任务被删除
     * TASK_COMPLETED_FORM_DATA_UPDATE 人工任务提交完成后，智能表单数据更新
     * <p>
     * 其中 create/complete/assignment/delete事件是需要在模型中人工节点上配置了委托代理表达式 ${taskBizCallListener}才会推送过来。
     * 在人工任务节点上配置 任务监听器  建议事件为 complete,其它assignment/create/complete/delete也可以，一般建议在complete,委托代理表达式 ${taskBizCallListener}
     *
     * @param flowVars {flowBranchId,agree,procInstId,startUserid,assignee,actId,taskName,mainTitle,branchId,bizKey,commentMsg,eventName,modelKey} 等
     * @return 如果tips.isOk==false，将影响流程提交
     **/
    @Transactional
    public void processApprova(IPage page, QueryWrapper ew, Map<String, Object> flowVars) {
        String eventName = (String) flowVars.get("eventName");
        String agree = (String) flowVars.get("agree");
        String branchId = (String) flowVars.get("branchId");
        String purOrderId = (String) flowVars.get("purOrderId");//资产采购编号
        String bizKey = (String) flowVars.get("bizKey");
        if ("erp_order_add_approva".equals(bizKey)) {
        } else {
            throw new BizException("不支持的业务,请上送业务编码【bizKey】参数");
        }

        if ("complete".equals(eventName)) {
            if ("1".equals(agree)) {
                this.updateFlowStateByProcInst(null, flowVars);
            } else {
                this.updateFlowStateByProcInst(null, flowVars);
            }
        } else {
            //废弃：监听资产管理员，create->待入库
            // PROCESS_COMPLETED->待入库
            if ("TASK_CREATED".equals(eventName)) {
                //办公用品管理员节点ID已写死为om_appliance_keeper
                /*if ("asset_keeper".equals(flowVars.get("actId"))) {
                    //流程表和采购单表更新为2,表示待入库
                    this.updateFlowStateByProcInst("2",flowVars);
                }*/
            } else {
                if ("PROCESS_STARTED".equals(eventName)) {
                    Map<String, Object> bizQuery = new HashMap<>();
                    bizQuery.put("id", purOrderId);
                    if (StringUtils.isEmpty(purOrderId)) {
                        throw new BizException("请上送资产采购单编号-purOrderId");
                    }
                    if (StringUtils.isEmpty(branchId)) {
                        throw new BizException("请上送branchId");
                    }
                    List<Map<String, Object>> bizList = this.selectListMapByWhere(page, ew, bizQuery);
                    if (bizList == null || bizList.size() == 0) {
                        throw new BizException("没有找到对应资产采购单,采购单为【" + purOrderId + "】");
                    } else {
                        Map<String, Object> bizObject = bizList.get(0);
                        if ("1".equals(bizObject.get("bizFlowState"))) {
                            throw new BizException("该资产采购单正在审批中，不能再发起审批");
                        }
                    }
                    this.updateFlowStateByProcInst("1", flowVars);
                } else if ("PROCESS_COMPLETED".equals(eventName)) {
                    //流程表、订单表更新
                    flowVars.put("flowEndTime", new Date());//传入任意数值，表示flowEndTime需要修改
                    if ("1".equals(agree)) {
                        //2为待入库状态，入库操作需要到资产入库处进行
                        this.updateFlowStateByProcInst("2", flowVars);
                    } else {
                        //5为未通过状态
                        this.updateFlowStateByProcInst("3", flowVars);
                    }
                } else if ("PROCESS_CANCELLED".equals(eventName)) {
                    //4为流程取消状态
                    flowVars.put("flowEndTime", new Date());//传入任意数值，表示flowEndTime需要修改
                    this.updateFlowStateByProcInst("4", flowVars);
                }
            }
        }
    }

    //update等级表状态、流程表信息
    public void updateFlowStateByProcInst(String flowState, Map<String, Object> flowVars) {
        flowVars.put("bizFlowState", flowState);
        flowVars.put("orderStatus", flowState);
        flowVars.put("id", flowVars.get("purOrderId"));
        if ("1".equals(flowState)) {
            flowVars.put("bizProcInstId", flowVars.get("procInstId"));
        }
//        this.updateSomeFieldByPk(flowVars);
        ObjectMapper objectMapper = new ObjectMapper();
        Order order = objectMapper.convertValue(flowVars, Order.class);
        baseMapper.updateById(order);
    }
}

